package org.example.mybatis.executor;

import org.example.mybatis.annotation.Param;
import org.example.mybatis.session.Configuration;
import org.example.mybatis.session.MappedStatement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 简单SQL执行器实现
 */
public class SimpleExecutor implements Executor {
    private static final Logger logger = LoggerFactory.getLogger(SimpleExecutor.class);

    private final Configuration configuration;

    public SimpleExecutor(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter) {
        Connection connection = configuration.getConnection();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            // 解析SQL语句
            BoundSql boundSql = getBoundSql(ms.getSql(), parameter);
            logger.info("执行SQL: {}", boundSql.getSql());
            logger.info("结果类型: {}", ms.getResultType());

            // 预编译SQL
            preparedStatement = connection.prepareStatement(boundSql.getSql());

            // 设置参数
            setParameters(preparedStatement, boundSql.getParameterMappings(), parameter);

            // 执行查询
            resultSet = preparedStatement.executeQuery();

            // 处理结果
            return handleResultSet(resultSet, ms.getResultType());
        } catch (Exception e) {
            logger.error("执行查询出错", e);
            throw new RuntimeException("执行查询出错: " + e.getMessage(), e);
        } finally {
            closeResultSet(resultSet);
            closeStatement(preparedStatement);
        }
    }

    @Override
    public int update(MappedStatement ms, Object parameter) {
        Connection connection = configuration.getConnection();
        PreparedStatement preparedStatement = null;

        try {
            // 解析SQL语句
            BoundSql boundSql = getBoundSql(ms.getSql(), parameter);
            logger.info("执行SQL: {}", boundSql.getSql());

            // 预编译SQL
            preparedStatement = connection.prepareStatement(boundSql.getSql());

            // 设置参数
            setParameters(preparedStatement, boundSql.getParameterMappings(), parameter);

            // 执行更新
            return preparedStatement.executeUpdate();
        } catch (Exception e) {
            logger.error("执行更新出错", e);
            throw new RuntimeException("执行更新出错", e);
        } finally {
            closeStatement(preparedStatement);
        }
    }

    /**
     * 解析SQL，替换占位符为?，并收集参数信息
     */
    private BoundSql getBoundSql(String sql, Object parameter) {
        List<ParameterMapping> parameterMappings = new ArrayList<>();

        // 将#{xxx}替换为?，并收集参数信息
        Pattern pattern = Pattern.compile("#\\{([^{}]+)\\}");
        Matcher matcher = pattern.matcher(sql);

        StringBuilder newSql = new StringBuilder();
        int start = 0;
        while (matcher.find()) {
            String paramName = matcher.group(1);
            parameterMappings.add(new ParameterMapping(paramName));

            newSql.append(sql, start, matcher.start()).append("?");
            start = matcher.end();
        }

        if (start < sql.length()) {
            newSql.append(sql.substring(start));
        }

        return new BoundSql(newSql.toString(), parameterMappings);
    }

    /**
     * 设置PreparedStatement的参数
     */
    private void setParameters(PreparedStatement ps, List<ParameterMapping> parameterMappings, Object parameter)
            throws SQLException, IllegalAccessException, NoSuchFieldException {
        if (parameter == null) {
            return;
        }

        // 处理基本类型或包装类型
        if (isPrimitive(parameter)) {
            if (parameterMappings.size() == 1) {
                ps.setObject(1, parameter);
            }
            return;
        }

        // 处理Map类型参数(多参数情况下)
        if (parameter instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> paramMap = (Map<String, Object>) parameter;
            for (int i = 0; i < parameterMappings.size(); i++) {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                String property = parameterMapping.getProperty();
                Object value = paramMap.get(property);
                ps.setObject(i + 1, value);
            }
            return;
        }

        // 处理普通对象类型，通过反射获取属性值
        Class<?> parameterClass = parameter.getClass();
        for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            try {
                Field field = parameterClass.getDeclaredField(parameterMapping.getProperty());
                field.setAccessible(true);
                Object value = field.get(parameter);
                ps.setObject(i + 1, value);
            } catch (NoSuchFieldException e) {
                // 可能是字段名称不匹配，尝试查找getter方法
                logger.warn("未找到字段: {}，将尝试查找getter方法", parameterMapping.getProperty());
                String getterMethodName = "get" + parameterMapping.getProperty().substring(0, 1).toUpperCase()
                        + parameterMapping.getProperty().substring(1);
                try {
                    Object value = parameterClass.getMethod(getterMethodName).invoke(parameter);
                    ps.setObject(i + 1, value);
                } catch (Exception ex) {
                    logger.error("无法获取参数值: {}", parameterMapping.getProperty(), ex);
                    throw new RuntimeException("无法获取参数值: " + parameterMapping.getProperty(), ex);
                }
            }
        }
    }

    /**
     * 判断是否为基本类型或包装类型
     */
    private boolean isPrimitive(Object obj) {
        Class<?> clazz = obj.getClass();
        return clazz.isPrimitive() ||
                clazz == Boolean.class ||
                clazz == Byte.class ||
                clazz == Character.class ||
                clazz == Short.class ||
                clazz == Integer.class ||
                clazz == Long.class ||
                clazz == Float.class ||
                clazz == Double.class ||
                clazz == String.class;
    }

    /**
     * 处理查询结果集
     */
    @SuppressWarnings("unchecked")
    private <E> List<E> handleResultSet(ResultSet rs, String resultType) throws Exception {
        List<E> list = new ArrayList<>();

        if (resultType == null || resultType.isEmpty()) {
            logger.warn("结果类型为空，返回空列表");
            return list;
        }

        logger.info("开始处理结果集，类型: {}", resultType);

        try {
            Class<?> entityClass = Class.forName(resultType);
            logger.info("成功加载结果类: {}", entityClass.getName());

            // 记录实体类的所有字段，帮助调试
            Field[] fields = entityClass.getDeclaredFields();
            StringBuilder fieldInfo = new StringBuilder("实体类字段信息: ");
            for (Field field : fields) {
                fieldInfo.append(field.getName()).append("(").append(field.getType().getSimpleName()).append("), ");
            }
            logger.info(fieldInfo.toString());

            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();

            // 记录列信息，帮助调试
            StringBuilder columnInfo = new StringBuilder("结果集列信息: ");
            for (int i = 1; i <= columnCount; i++) {
                columnInfo.append(metaData.getColumnName(i)).append("(").append(metaData.getColumnTypeName(i)).append("), ");
            }
            logger.info(columnInfo.toString());

            while (rs.next()) {
                // 创建结果对象实例
                Object entity = entityClass.getDeclaredConstructor().newInstance();
                logger.debug("创建实体对象: {}", entity.getClass().getName());

                for (int i = 1; i <= columnCount; i++) {
                    String columnName = metaData.getColumnName(i);
                    Object columnValue = rs.getObject(i);

                    // 跳过空值
                    if (columnValue == null) {
                        continue;
                    }

                    logger.debug("处理列: {} = {} (类型: {})", columnName, columnValue, columnValue.getClass().getName());

                    // 查找对应的Field
                    try {
                        Field field = entityClass.getDeclaredField(columnName);
                        field.setAccessible(true);
                        Object convertedValue = convertValue(columnValue, field.getType());
                        field.set(entity, convertedValue);
                        logger.debug("设置字段: {} = {} (转换后类型: {})", field.getName(), convertedValue,
                                convertedValue != null ? convertedValue.getClass().getName() : "null");
                    } catch (NoSuchFieldException e) {
                        // 尝试将下划线命名转为驼峰命名
                        String camelColumnName = toCamelCase(columnName);
                        logger.debug("尝试驼峰命名: {} -> {}", columnName, camelColumnName);
                        try {
                            Field field = entityClass.getDeclaredField(camelColumnName);
                            field.setAccessible(true);
                            Object convertedValue = convertValue(columnValue, field.getType());
                            field.set(entity, convertedValue);
                            logger.debug("设置驼峰字段: {} = {} (转换后类型: {})", field.getName(), convertedValue,
                                    convertedValue != null ? convertedValue.getClass().getName() : "null");
                        } catch (NoSuchFieldException ex) {
                            // 字段名可能和列名不一致，这里简单忽略
                            logger.warn("找不到字段: {} 或 {}", columnName, camelColumnName);
                        }
                    }
                }

                list.add((E) entity);
            }

            logger.info("处理结果集完成，共 {} 条记录", list.size());
        } catch (ClassNotFoundException e) {
            logger.error("找不到结果类型: {}", resultType, e);
            throw new RuntimeException("找不到结果类型: " + resultType, e);
        } catch (Exception e) {
            logger.error("处理结果集时发生错误", e);
            throw e;
        }

        return list;
    }

    /**
     * 将下划线命名转为驼峰命名
     */
    private String toCamelCase(String name) {
        StringBuilder result = new StringBuilder();
        boolean nextUpper = false;

        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);
            if (c == '_') {
                nextUpper = true;
            } else {
                if (nextUpper) {
                    result.append(Character.toUpperCase(c));
                    nextUpper = false;
                } else {
                    result.append(Character.toLowerCase(c));
                }
            }
        }

        return result.toString();
    }

    /**
     * 根据字段类型转换值
     */
    private Object convertValue(Object value, Class<?> type) {
        if (value == null) {
            return null;
        }

        if (type.isAssignableFrom(value.getClass())) {
            return value;
        }

        // 日期类型转换
        if (type == java.util.Date.class) {
            if (value instanceof java.sql.Date || value instanceof java.sql.Timestamp) {
                // SQL日期/时间戳转为Java日期
                return new java.util.Date(((java.util.Date) value).getTime());
            }
        }

        // 基本类型转换
        if (type == Integer.class || type == int.class) {
            return Integer.valueOf(value.toString());
        } else if (type == Long.class || type == long.class) {
            return Long.valueOf(value.toString());
        } else if (type == Double.class || type == double.class) {
            return Double.valueOf(value.toString());
        } else if (type == Boolean.class || type == boolean.class) {
            return Boolean.valueOf(value.toString());
        }

        return value;
    }

    /**
     * 关闭ResultSet
     */
    private void closeResultSet(ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                logger.error("关闭ResultSet出错", e);
            }
        }
    }

    /**
     * 关闭Statement
     */
    private void closeStatement(PreparedStatement stmt) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                logger.error("关闭Statement出错", e);
            }
        }
    }

    /**
     * 表示解析后的SQL及参数信息
     */
    private static class BoundSql {
        private final String sql;
        private final List<ParameterMapping> parameterMappings;

        public BoundSql(String sql, List<ParameterMapping> parameterMappings) {
            this.sql = sql;
            this.parameterMappings = parameterMappings;
        }

        public String getSql() {
            return sql;
        }

        public List<ParameterMapping> getParameterMappings() {
            return parameterMappings;
        }
    }

    /**
     * 表示SQL中的参数
     */
    private static class ParameterMapping {
        private final String property;

        public ParameterMapping(String property) {
            this.property = property;
        }

        public String getProperty() {
            return property;
        }
    }
}